from decorators import Transactional
from enums.menu_app_code_enum import MenuAppCodeEnum
from mauth.login_user_holder import LoginUserHolder
from models.menu import Menu
from models.role_menu import RoleMenu
from services import BaseService
from tools import build_tree, generate_id
from tools.db_tool import DbTool
from sqlalchemy import asc


class MenuService(BaseService):
    """
    菜单模块业务处理类
    """
    def app_list(self):
        """
        应用列表
        """
        res = []
        for member in MenuAppCodeEnum:
            res.append({
                'label': member.msg,
                'value': member.name.lower()
            })
        return res
    def list(self):
        """
        菜单列表
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return Menu.to_dict_list(list)
    def tree(self):
        """
        菜单树
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return build_tree(Menu.to_dict_list(list))
    @Transactional()
    def sync_route(self,routeList):
        """
        同步路由
        """
        menuIds = []
        if routeList is not None and len(routeList) > 0:
            # 一级菜单
            for route in routeList:
                isSync = route.get('isSync')
                if isSync == 1:
                    menuId = self.save_or_update_route(route, 0)
                    menuIds.append(menuId)
                    # 二级菜单
                    if route.get('children') is not None and len(route.get('children')) > 0:
                        for child in route.get('children'):
                            menuId2 = self.save_or_update_route(child, menuId)
                            menuIds.append(menuId2)
                            # 三级菜单
                            if child.get('children') is not None and len(child.get('children')) > 0:
                                for grandson in child.get('children'):
                                    menuId3 = self.save_or_update_route(grandson, menuId2)
                                    menuIds.append(menuId3)
                                    # 四级菜单
                                    if grandson.get('children') is not None and len(grandson.get('children')) > 0:
                                        for greatGrandson in grandson.get('children'):
                                            menuId4 = self.save_or_update_route(greatGrandson, menuId3)
                                            menuIds.append(menuId4)
        # 删除前端同步菜单、当前应用、不在当前同步菜单内的路由菜单
        appCode = LoginUserHolder.get_app_code()
        if len(menuIds) == 0:
            menuIds.append(0)
        self.db.session.query(Menu).filter(Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds)).delete()

        sysMenus = self.db.session.query(Menu).filter(Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds)).all()
        if len(sysMenus) > 0:
           deleteMenuIds = [menu.id for menu in sysMenus]
           # 删除冗余菜单
           self.db.session.query(Menu).filter(Menu.id.in_(deleteMenuIds)).delete()
           # 清除角色菜单关联表
           self.db.session.query(RoleMenu).filter(RoleMenu.menuId.in_(deleteMenuIds)).delete()
    def save_or_update_route(self,route, pid):
        """
        保存或更新路由
        """
        menu = Menu(**route)
        menu.code = route.get('code')
        menu.appCode = LoginUserHolder.get_app_code()
        menu.parentId = pid
        menu.pids = ''
        if(menu.openType is None) :
            menu.openType = 0
        newPids = self.create_new_pids(pid)
        menu.pids = newPids
        menu.variable = "{}"
        oldMenu = self.get_menu(menu.code, pid)
        if oldMenu is not None:
            # 存在则更新
            menu.updateUser = LoginUserHolder.get_user_id()
            self.db.session.query(Menu).filter_by(id=oldMenu.id).update(menu.to_dict())
            return oldMenu.id
        else:
            menu.createUser = LoginUserHolder.get_user_id()
            menu.updateUser = LoginUserHolder.get_user_id()
            menu.id = generate_id()
            self.db.session.add(menu)
            return menu.id

            
    def create_new_pids(self, pid):
        if pid == 0:
            return "[" + str(pid) + "]" +","
        else:
            # 获取父菜单
            parentMenu = self.db.session.query(Menu).filter_by(id=pid).first()
            if parentMenu is not None:
                print('pids:'+parentMenu.pids)
                return parentMenu.pids + "[" + str(pid) + "]" +","
    def get_menu(self, code, pid):
        """
        根据code获取菜单
        """
        appCode = LoginUserHolder.get_app_code()
        return self.db.session.query(Menu).filter_by(code=code, parentId=pid, appCode=appCode).first()